/**
 * File Name: SchemaChecker.java
 * Description: 
 * Create Time: 2010-12-16  
 * @author yue.chen  (yue.chen2@hisoft.com)
 */
package com.hisoft.xml;

import java.io.File;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.SAXParseException;

import com.hisoft.type.XMLType;
import com.hisoft.utility.CommonTool;

public class SchemaChecker {
	static Logger logger = Logger.getLogger(SchemaChecker.class);
	private static final String CONFIG_SCHEMA = "schema/config.xsd";
	private static final String TESTCASE_SCHEMA = "schema/testcase.xsd";
	private static final String WEBSITE_SCHEMA = "schema/website.xsd";

	/**
	 * Validates the XML file.
	 * 
	 * <b> This is just a method for validate XML with Schema </b>
	 * 
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	private static boolean validateSingleSchema(File xml, File xsd) {
		boolean legal = false;
		try {
			if (fileExists(xml) && fileExists(xsd)) {
				SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
				Schema schema = sf.newSchema(xsd);
				Validator validator = schema.newValidator();
				validator.validate(new StreamSource(xml));
				legal = true;
			}
		} catch (SAXParseException spe) {
			logger.error("file '" + xml.getPath() + "' " + spe.getMessage(), spe);
			legal = false;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			legal = false;
		}
		return legal;
	}

	/**
	 * 
	 * 
	 * <b></b><br/>
	 * 
	 * @Author chenyue ( yue.chen2@hisoft.com ) Create on 2011-9-1
	 */
	private boolean validateSingleSchemaV2(File xml, File xsd) {
		boolean legal = false;
		try {
			if (fileExists(xml) && fileExists(xsd)) {
				SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
				Schema schema = sf.newSchema(xsd);
				Validator validator = schema.newValidator();
				validator.validate(new StreamSource(xml));
				legal = true;
			}
		} catch (SAXParseException spe) {
			legal = false;
		} catch (Exception e) {
			legal = false;
		}
		return legal;
	}

	/**
	 * validate Only XML.
	 * 
	 * <b> This is a XML validator to help you check the syntax of XML. </b>
	 * 
	 * @throws SAXParseException
	 * 
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	public static boolean validateOnlyXml(File xmlFile) {
		boolean legal = false;
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(xmlFile);
			doc.getDocumentElement().normalize();
			legal = true;
		} catch (SAXParseException spe) {
			logger.error(spe.getMessage(), spe);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return legal;
	}

	/**
	 * File Exists.
	 * 
	 * <b> Handling the situation that file does not exist. </b>
	 * 
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	public static boolean fileExists(File file) {
		if (!file.exists()) {
			// ExceptionHandle.fileError("File '" + file.getPath() +
			// "' not found.", new Throwable());
		}
		return file.exists();
	}

	/**
	 * validate Xml.
	 * 
	 * <b> validate the XML with a Single Schema. </b>
	 * 
	 * @param File
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	public static boolean validateXml(File xmlFile, XMLType xt) {
		return validateSingleSchema(xmlFile, getXsdFile(xt));
	}

	public boolean validateXmlV2(File xmlFile, XMLType xt) {
		return validateSingleSchemaV2(xmlFile, getXsdFile(xt));
	}

	/**
	 * validate Xml.
	 * 
	 * <b> validate the XML with a Single Schema. </b>
	 * 
	 * @param String
	 *            the string can be a file path or a directory
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	public static boolean validateXml(String xmlFilePath, XMLType xt) {
		File tempFile = new File(xmlFilePath);
		if (tempFile.exists()) {
			if (tempFile.isDirectory()) {
				return validateXml(CommonTool.readXmlFileList(xmlFilePath), xt);
			} else {
				return validateXml(new File(xmlFilePath), xt);
			}
		} else {
			logger.info("the path: '" + xmlFilePath + "'  does not exist!");
			return true;
		}
	}

	/**
	 * validate Xml.
	 * 
	 * <b> validate the XML with a Single Schema. </b>
	 * 
	 * @param List
	 *            <File>
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 */
	public static boolean validateXml(List<File> files, XMLType xt) {
		boolean legal = true;
		switch (xt) {
		case CONFIG:
			logger.info("check the CONFIG XML...");
			break;
		case TESTCASE:
			logger.info("check the TESTCASE XML...");
			break;
		case WEBSITE:
			logger.info("check the WEBSITE XML...");
			break;
		default:
			logger.info("if you see this, XML type has been changed. please fix your code.");
			break;
		}
		for (int i = 0; i < files.size(); i++) {
			legal = validateXml(files.get(i), xt) && legal;
		}
		return legal;
	}

	/**
	 * <b>use the attribute named "noNamespaceSchemaLocation" to know the Schema
	 * Location and return the File ,if it exists.</b>
	 * 
	 * @Author yue.chen ( yue.chen2@hisoft.com )
	 * 
	 */
	private static File getXsdFile(XMLType xt) {
		switch (xt) {
		case CONFIG:
			return new File(CONFIG_SCHEMA);
		case TESTCASE:
			return new File(TESTCASE_SCHEMA);
		case WEBSITE:
			return new File(WEBSITE_SCHEMA);
		default:
			return null;
		}
	}

}
